#include <memory>
#include "ILogCallBack.h"
using namespace std;

class LogHelper
{
public:
	static LogHelper& GetInstance()
	{
		static LogHelper instance;
		return instance;
	}
	void SetSink(ILogCallBack& sink);
	void Debug(string msg);
	void Info(string msg);
	void Warn(string msg);
	void Error(string msg);

private:
	LogHelper() = default;
	~LogHelper() = default;
	LogHelper(const LogHelper&) = delete;
	LogHelper& operator=(const LogHelper&) = delete;
	ILogCallBack* logCallBack;
};


#define LOG_DEBUG() LogHelper::GetInstance().Debug(string(__FUNCTION__))
#define LOG_INFO() LogHelper::GetInstance().Info(string(__FUNCTION__))
#define LOG_WARN() LogHelper::GetInstance().Warn(string(__FUNCTION__))
#define LOG_ERROR() LogHelper::GetInstance().Error(string(__FUNCTION__))

#define LOG_FUNCTION() \
    LogHelper::GetInstance().Info(string(__FUNCTION__) + " - Start"); \
    auto log_function_guard = make_scope_exit([]{ \
        LogHelper::GetInstance().Info(string(__FUNCTION__) + " - End"); \
    })

template <typename F>
class ScopeExit {
public:
    explicit ScopeExit(F&& f) : f_(std::forward<F>(f)), active_(true) {}
    ~ScopeExit() { if (active_) f_(); }
    ScopeExit(ScopeExit&& other) : f_(std::move(other.f_)), active_(other.active_) { other.active_ = false; }
    ScopeExit& operator=(ScopeExit&& other) {
        if (this != &other) {
            f_ = std::move(other.f_);
            active_ = other.active_;
            other.active_ = false;
        }
        return *this;
    }
    void release() { active_ = false; }
private:
    F f_;
    bool active_;
};

template <typename F>
ScopeExit<F> make_scope_exit(F&& f) {
    return ScopeExit<F>(std::forward<F>(f));
}